
/*
 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_LICENSE_HEADER_END@
 */

/*!
 @header		CommonCryptor.h
 @abstract	Generic interface for symmetric encryption.
 
 @discussion	This interface provides access to a number of symmetric encryption
 algorithms. Symmetric encryption algorithms come in two "flavors" -
 block ciphers, and stream ciphers. Block ciphers process data
 (while both encrypting and decrypting) in discrete chunks of
 data called blocks; stream ciphers operate on arbitrary sized
 data.
 
 The object declared in this interface, CCCryptor, provides
 access to both block ciphers and stream ciphers with the same
 API; however some options are available for block ciphers that
 do not apply to stream ciphers.
 
 The general operation of a CCCryptor is: initialize it
 with raw key data and other optional fields with CCCryptorCreate();
 process input data via one or more calls to CCCryptorUpdate(),
 each of which may result in output data being written to
 caller-supplied memory; and obtain possible remaining output data
 with CCCryptorFinal(). The CCCryptor is disposed of via
 CCCryptorRelease(), or it can be reused (with the same key data
 as provided to CCCryptorCreate()) by calling CCCryptorReset().
 
 CCCryptors can be dynamically allocated by this module, or
 their memory can be allocated by the caller. See discussion for
 CCCryptorCreate() and CCCryptorCreateFromData() for information
 on CCCryptor allocation.
 
 One option for block ciphers is padding, as defined in PKCS7;
 when padding is enabled, the total amount of data encrypted
 does not have to be an even multiple of the block size, and
 the actual length of plaintext is calculated during decryption.
 
 Another option for block ciphers is Cipher Block Chaining, known
 as CBC mode. When using CBC mode, an Initialization Vector (IV)
 is provided along with the key when starting an encrypt
 or decrypt operation. If CBC mode is selected and no IV is
 provided, an IV of all zeroes will be used.
 
 CCCryptor also implements block bufferring, so that individual
 calls to CCCryptorUpdate() do not have to provide data whose length
 is aligned to the block size. (If padding is disabled, encrypting
 with block ciphers does require that the *total* length of data
 input to CCCryptorUpdate() call(s) be aligned to the block size.)
 
 A given CCCryptor can only be used by one thread at a time;
 multiple threads can use safely different CCCryptors at the
 same time.
 */

#ifndef	_CC_COMMON_CRYPTOR_
#define	_CC_COMMON_CRYPTOR_

#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif
    
    /*!
     @typedef	CCCryptorRef
     @abstract	Opaque reference to a CCCryptor object.
     */
    typedef struct _CCCryptor *CCCryptorRef;
    
    /*!
     @enum		CCCryptorStatus
     @abstract	Return values from CommonCryptor operations.
     
     @constant	kCCSuccess			Operation completed normally.
     @constant	kCCParamError		Illegal parameter value.
     @constant	kCCBufferTooSmall	Insufficent buffer provided for specified operation.
     @constant	kCCMemoryFailure	Memory allocation failure.
     @constant	kCCAlignmentError	Input size was not aligned properly.
     @constant	kCCDecodeError		Input data did not decode or decrypt properly.
     @constant	kCCUnimplemented	Function not implemented for the current algorithm.
     */
    enum {
        kCCSuccess			= 0,
        kCCParamError		= -4300,
        kCCBufferTooSmall	= -4301,
        kCCMemoryFailure	= -4302,
        kCCAlignmentError	= -4303,
        kCCDecodeError		= -4304,
        kCCUnimplemented	= -4305
    };
    typedef int32_t CCCryptorStatus;
    
    /*!
     @enum		CCOperation
     @abstract	Operations that an CCCryptor can perform.
     
     @constant	kCCEncrypt	Symmetric encryption.
     @constant	kCCDecrypt	Symmetric decryption.
     */
    enum {
        kCCEncrypt = 0,
        kCCDecrypt,
    };
    typedef uint32_t CCOperation;
    
    /*!
     @enum		CCAlgorithm
     @abstract	Encryption algorithms implemented by this module.
     
     @constant	kCCAlgorithmAES128	Advanced Encryption Standard, 128-bit block
     @constant	kCCAlgorithmDES		Data Encryption Standard
     @constant	kCCAlgorithm3DES	Triple-DES, three key, EDE configuration
     @constant	kCCAlgorithmCAST	CAST
     @constant	kCCAlgorithmRC4		RC4 stream cipher
     */
    enum {
        kCCAlgorithmAES128 = 0,
        kCCAlgorithmDES,
        kCCAlgorithm3DES,
        kCCAlgorithmCAST,
        kCCAlgorithmRC4,
        kCCAlgorithmRC2
    };
    typedef uint32_t CCAlgorithm;
    
    /*!
     @enum		CCOptions
     @abstract	Options flags, passed to CCCryptorCreate().
     
     @constant	kCCOptionPKCS7Padding	Perform PKCS7 padding.
     @constant	kCCOptionECBMode		Electronic Code Book Mode.
     Default is CBC.
     */
    enum {
        /* options for block ciphers */
        kCCOptionPKCS7Padding	= 0x0001,
        kCCOptionECBMode		= 0x0002
        /* stream ciphers currently have no options */
    };
    typedef uint32_t CCOptions;
    
    /*!
     @enum			Key sizes
     
     @discussion		Key sizes, in bytes, for supported algorithms.
     
     @constant kCCKeySizeAES128		128 bit AES key size.
     @constant kCCKeySizeAES192		192 bit AES key size.
     @constant kCCKeySizeAES256		256 bit AES key size.
     @constant kCCKeySizeDES			DES key size.
     @constant kCCKeySize3DES		Triple DES key size.
     @constant kCCKeySizeMinCAST		CAST minimum key size.
     @constant kCCKeySizeMaxCAST		CAST maximum key size.
     @constant kCCKeySizeMinRC4		RC4 minimum key size.
     @constant kCCKeySizeMaxRC4		RC4 maximum key size.
     
     @discussion		DES and TripleDES have fixed key sizes.
     AES has three discrete key sizes.
     CAST and RC4 have variable key sizes.
     */
    enum {
        kCCKeySizeAES128	= 16,
        kCCKeySizeAES192	= 24,
        kCCKeySizeAES256	= 32,
        kCCKeySizeDES		= 8,
        kCCKeySize3DES		= 24,
        kCCKeySizeMinCAST	= 5,
        kCCKeySizeMaxCAST	= 16,
        kCCKeySizeMinRC4	= 1,
        kCCKeySizeMaxRC4	= 512,
        kCCKeySizeMinRC2	= 1,
        kCCKeySizeMaxRC2	= 128
    };
    
    /*!
     @enum			Block sizes
     
     @discussion		Block sizes, in bytes, for supported algorithms.
     
     @constant kCCBlockSizeAES128	AES block size (currently, only 128-bit
     blocks are supported).
     @constant kCCBlockSizeDES		DES block size.
     @constant kCCBlockSize3DES		Triple DES block size.
     @constant kCCBlockSizeCAST		CAST block size.
     */
    enum {
        /* AES */
        kCCBlockSizeAES128	= 16,
        /* DES */
        kCCBlockSizeDES		= 8,
        /* 3DES */
        kCCBlockSize3DES	= 8,
        /* CAST */
        kCCBlockSizeCAST	= 8,
        kCCBlockSizeRC2		= 8,
    };
    
    /*!
     @enum		Minimum context sizes
     @discussion	Minimum context sizes, for caller-allocated CCCryptorRefs.
     To minimize dynamic allocation memory, a caller can create
     a CCCryptorRef by passing caller-supplied memory to the
     CCCryptorCreateFromData() function.
     
     These constants define the minimum amount of memory, in
     bytes, needed for CCCryptorRefs for each supported algorithm.
     
     Note: these constants are valid for the current version of
     this library; they may change in subsequent releases, so
     applications wishing to allocate their own memory for use
     in creating CCCryptorRefs must be prepared to deal with
     a kCCBufferTooSmall return from CCCryptorCreateFromData().
     See discussion for the CCCryptorCreateFromData() function.
     
     @constant kCCContextSizeAES128		Minimum context size for kCCAlgorithmAES128.
     @constant kCCContextSizeDES			Minimum context size for kCCAlgorithmAES128.
     @constant kCCContextSize3DES		Minimum context size for kCCAlgorithmAES128.
     @constant kCCContextSizeCAST		Minimum context size for kCCAlgorithmCAST.
     @constant kCCContextSizeRC4			Minimum context size for kCCAlgorithmRC4.
     */
    enum {
        kCCContextSizeAES128	= 404,
        kCCContextSizeDES		= 240,
        kCCContextSize3DES		= 496,
        kCCContextSizeCAST		= 240,
        kCCContextSizeRC4		= 1072
    };
    
    /*!
     @function	CCCryptorCreate
     @abstract	Create a cryptographic context.
     
     @param		op			Defines the basic operation: kCCEncrypt or kCCDecrypt.
     
     @param		alg			Defines the algorithm.
     
     @param		options		A word of flags defining options. See discussion
     for the CCOptions type.
     
     @param		key			Raw key material, length keyLength bytes.
     
     @param		keyLength	Length of key material. Must be appropriate
     for	the selected operation and algorithm. Some
     algorithms  provide for varying key lengths.
     
     @param		iv			Initialization vector, optional. Used by
     block ciphers when Cipher Block Chaining (CBC)
     mode is enabled. If present, must be the same
     length as the selected algorithm's block size.
     If CBC mode is selected (by the absence of the
     kCCOptionECBMode bit in the options flags) and no
     IV is present, a NULL (all zeroes) IV will be used.
     This parameter is ignored if ECB mode is used or
     if a stream cipher algorithm is selected.
     
     @param		cryptorRef	A (required) pointer to the returned CCCryptorRef.
     
     @result		Possible error returns are kCCParamError and kCCMemoryFailure.
     */
    CCCryptorStatus CCCryptorCreate(
                                    CCOperation op,             /* kCCEncrypt, etc. */
                                    CCAlgorithm alg,            /* kCCAlgorithmDES, etc. */
                                    CCOptions options,          /* kCCOptionPKCS7Padding, etc. */
                                    const void *key,            /* raw key material */
                                    size_t keyLength,
                                    const void *iv,             /* optional initialization vector */
                                    CCCryptorRef *cryptorRef);  /* RETURNED */
    
    /*!
     @function	CCCryptorCreateFromData
     @abstract	Create a cryptographic context using caller-supplied memory.
     
     @param		op			Defines the basic operation: kCCEncrypt or kCCDecrypt.
     
     @param		alg			Defines the algorithm.
     
     @param		options		A word of flags defining options. See discussion
     for the CCOptions type.
     
     @param		key			Raw key material, length keyLength bytes.
     
     @param		keyLength	Length of key material. Must be appropriate
     for	the selected operation and algorithm. Some
     algorithms  provide for varying key lengths.
     
     @param		iv			Initialization vector, optional. Used by
     block ciphers when Cipher Block Chaining (CBC)
     mode is enabled. If present, must be the same
     length as the selected algorithm's block size.
     If CBC mode is selected (by the absence of the
     kCCOptionECBMode bit in the options flags) and no
     IV is present, a NULL (all zeroes) IV will be used.
     This parameter is ignored if ECB mode is used or
     if a stream cipher algorithm is selected.
     
     @param		data		A pointer to caller-supplied memory from which the
     CCCryptorRef will be created.
     
     @param		dataLength	The size of the caller-supplied memory in bytes.
     
     @param		cryptorRef	A (required) pointer to the returned CCCryptorRef.
     
     @param		dataUsed	Optional. If present, the actual number of bytes of
     the caller-supplied memory which was consumed by
     creation of the CCCryptorRef is returned here. Also,
     if the supplied memory is of insufficent size to create
     a CCCryptorRef, kCCBufferTooSmall is returned, and
     the minimum required buffer size is returned via this
     parameter if present.
     
     @result		Possible error returns are kCCParamError and kCCBufferTooSmall.
     
     @discussion	The CCCryptorRef created by this function *may* be disposed of
     via CCCRyptorRelease; that call is not strictly necessary, but
     if it's not performed, good security practice dictates that the
     caller should zero the memory provided to create the CCCryptorRef
     when the caller is finished using the CCCryptorRef.
     */
    CCCryptorStatus CCCryptorCreateFromData(
                                            CCOperation op,             /* kCCEncrypt, etc. */
                                            CCAlgorithm alg,            /* kCCAlgorithmDES, etc. */
                                            CCOptions options,          /* kCCOptionPKCS7Padding, etc. */
                                            const void *key,            /* raw key material */
                                            size_t keyLength,
                                            const void *iv,             /* optional initialization vector */
                                            const void *data,			/* caller-supplied memory */
                                            size_t dataLength,			/* length of data in bytes */
                                            CCCryptorRef *cryptorRef,   /* RETURNED */
                                            size_t *dataUsed);			/* optional, RETURNED */
    
    /*!
     @function	CCCryptorRelease
     @abstract	Free a context created by CCCryptorCreate or
     CCCryptorCreateFromData().
     
     @param		cryptorRef	The CCCryptorRef to release.
     
     @result		The only possible error return is kCCParamError resulting
     from passing in a null CCCryptorRef.
     */
    CCCryptorStatus CCCryptorRelease(
                                     CCCryptorRef cryptorRef);
	
    /*!
     @function	CCCryptorUpdate
     @abstract	Process (encrypt, decrypt) some data. The result, if any,
     is written to a caller-provided buffer.
     
     @param		cryptorRef		A CCCryptorRef created via CCCryptorCreate() or
     CCCryptorCreateFromData().
     @param		dataIn			Data to process, length dataInLength bytes.
     @param		dataInLength	Length of data to process.
     @param		dataOut			Result is written here. Allocated by caller.
     Encryption and decryption can be performed
     "in-place", with the same buffer used for
     input and output.
     @param		dataOutAvailable The size of the dataOut buffer in bytes.
     @param		dataOutMoved	On successful return, the number of bytes written
     to dataOut.
     
     @result		kCCBufferTooSmall indicates insufficent space in the dataOut
     buffer. The caller can use CCCryptorGetOutputLength()
     to determine the required output buffer size in this
     case. The operation can be retried; no state is lost
     when this is returned.
     
     @discussion	This routine can be called multiple times. The caller does
     not need to align input data lengths to block sizes; input is
     bufferred as necessary for block ciphers.
     
     When performing symmetric encryption with block ciphers,
     and padding is enabled via kCCOptionPKCS7Padding, the total
     number of bytes provided by all the calls to this function
     when encrypting can be arbitrary (i.e., the total number
     of bytes does not have to be block aligned). However if
     padding is disabled, or when decrypting, the total number
     of bytes does have to be aligned to the block size; otherwise
     CCCryptFinal() will return kCCAlignmentError.
     
     A general rule for the size of the output buffer which must be
     provided by the caller is that for block ciphers, the output
     length is never larger than the input length plus the block size.
     For stream ciphers, the output length is always exactly the same
     as the input length. See the discussion for CCCryptorGetOutputLength()
     for more information on this topic.
     
     Generally, when all data has been processed, call CCCryptorFinal().
     In the following cases, the CCCryptorFinal() is superfluous as
     it will not yield any data nor return an error:
     1. Encrypting or decrypting with a block cipher with padding
     disabled, when the total amount of data provided to
     CCCryptorUpdate() is an integral multiple of the block size.
     2. Encrypting or decrypting with a stream cipher.
     */
    CCCryptorStatus CCCryptorUpdate(
                                    CCCryptorRef cryptorRef,
                                    const void *dataIn,
                                    size_t dataInLength,
                                    void *dataOut,				/* data RETURNED here */
                                    size_t dataOutAvailable,
                                    size_t *dataOutMoved);		/* number of bytes written */
    
    /*!
     @function	CCCryptorFinal
     @abstract	Finish an encrypt or decrypt operation, and obtain the (possible)
     final data output.
     
     @param		cryptorRef		A CCCryptorRef created via CCCryptorCreate() or
     CCCryptorCreateFromData().
     @param		dataOut			Result is written here. Allocated by caller.
     @param		dataOutAvailable The size of the dataOut buffer in bytes.
     @param		dataOutMoved	On successful return, the number of bytes written
     to dataOut.
     
     @result		kCCBufferTooSmall indicates insufficent space in the dataOut
     buffer. The caller can use CCCryptorGetOutputLength()
     to determine the required output buffer size in this
     case. The operation can be retried; no state is lost
     when this is returned.
     kCCAlignmentError When decrypting, or when encrypting with a
     block cipher with padding disabled,
     kCCAlignmentError will be returned if the total
     number of bytes provided to CCCryptUpdate() is
     not an integral multiple of	the current
     algorithm's block size.
     kCCDecodeError  Indicates garbled ciphertext or the
     wrong key during decryption. This can only
     be returned while decrypting with padding
     enabled.
     
     @discussion	Except when kCCBufferTooSmall is returned, the CCCryptorRef
     can no longer be used for subsequent operations unless
     CCCryptorReset() is called on it.
     
     It is not necessary to call CCCryptorFinal() when performing
     symmetric encryption or decryption if padding is disabled, or
     when using a stream cipher.
     
     It is not necessary to call CCCryptorFinal() prior to
     CCCryptorRelease() when aborting an operation.
     */
    CCCryptorStatus CCCryptorFinal(
                                   CCCryptorRef cryptorRef,
                                   void *dataOut,
                                   size_t dataOutAvailable,
                                   size_t *dataOutMoved);		/* number of bytes written */
    
    /*!
     @function	CCCryptorGetOutputLength
     @abstract	Determine output buffer size required to process a given input size.
     
     @param		cryptorRef	A CCCryptorRef created via CCCryptorCreate() or
     CCCryptorCreateFromData().
     @param		inputLength	The length of data which will be provided to
     CCCryptorUpdate().
     @param		final		If false, the returned value will indicate the output
     buffer space needed when 'inputLength' bytes are
     provided to	CCCryptorUpdate(). When 'final' is true,
     the returned value will indicate the total combined
     buffer space needed when 'inputLength' bytes are
     provided to	CCCryptorUpdate() and then CCCryptorFinal()
     is called.
     
     @result The maximum buffer space need to perform CCCryptorUpdate() and optionally
     CCCryptorFinal().
     
     @discussion	Some general rules apply that allow clients of this module to
     know a priori how much output buffer space will be required
     in a given situation. For stream ciphers, the output size is
     always equal to the input size, and CCCryptorFinal() never
     produces any data. For block ciphers, the output size will
     always be less than or equal to the input size plus the size
     of one block. For block ciphers, if the input size provided
     to each call to CCCryptorUpdate() is is an integral multiple
     of the block size, then the output size for each call to
     CCCryptorUpdate() is less than or equal to the input size
     for that call to CCCryptorUpdate(). CCCryptorFinal() only
     produces output when using a block cipher with padding enabled.
     */
    size_t CCCryptorGetOutputLength(
                                    CCCryptorRef cryptorRef,
                                    size_t inputLength,
                                    bool final);
	
    /*!
     @function	CCCryptorReset
     @abstract	Reinitializes an existing CCCryptorRef with a (possibly)
     new initialization vector. The CCCryptorRef's key is
     unchanged. Not implemented for stream ciphers.
     
     @param		cryptorRef	A CCCryptorRef created via CCCryptorCreate() or
     CCCryptorCreateFromData().
     @param		iv			Optional initialization vector; if present, must
     be the same size as the current algorithm's block
     size.
     
     @result		The the only possible errors are kCCParamError and
     kCCUnimplemented.
     
     @discussion This can be called on a CCCryptorRef with data pending (i.e.
     in a padded mode operation before CCCryptFinal is called);
     however any pending data will be lost in that case.
     */
    CCCryptorStatus CCCryptorReset(
                                   CCCryptorRef cryptorRef,
                                   const void *iv);
    
    /*!
     @function	CCCrypt
     @abstract	Stateless, one-shot encrypt or decrypt operation.
     This basically performs a sequence of CCCrytorCreate(),
     CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease().
     
     @param		alg				Defines the encryption algorithm.
     
     
     @param		op				Defines the basic operation: kCCEncrypt or kCCDecrypt.
     
     @param		options			A word of flags defining options. See discussion
     for the CCOptions type.
     
     @param		key				Raw key material, length keyLength bytes.
     
     @param		keyLength		Length of key material. Must be appropriate
     for	the select algorithm. Some algorithms may
     provide for varying key lengths.
     
     @param		iv				Initialization vector, optional. Used for
     Cipher Block Chaining (CBC) mode. If present,
     must be the same length as the selected 
     algorithm's block size. If CBC mode is
     selected (by the absence of any mode bits in 
     the options	flags) and no IV is present, a 
     NULL (all zeroes) IV will be used. This is 
     ignored if ECB mode is used or if a stream 
     cipher algorithm is selected. 
     
     @param		dataIn			Data to encrypt or decrypt, length dataInLength 
     bytes. 
     
     @param		dataInLength	Length of data to encrypt or decrypt.
     
     @param		dataOut			Result is written here. Allocated by caller. 
     Encryption and decryption can be performed
     "in-place", with the same buffer used for 
     input and output. 
     
     @param		dataOutAvailable The size of the dataOut buffer in bytes.  
     
     @param		dataOutMoved	On successful return, the number of bytes written 
     to dataOut. If kCCBufferTooSmall is returned as 
     a result of insufficient buffer space being 
     provided, the required buffer space is returned
     here. 
     
     @result		kCCBufferTooSmall indicates insufficent space in the dataOut
     buffer. In this case, the *dataOutMoved 
     parameter will indicate the size of the buffer
     needed to complete the operation. The 
     operation can be retried with minimal runtime 
     penalty. 
     kCCAlignmentError indicates that dataInLength was not properly 
     algined. This can only be returned for block 
     ciphers, and then only when decrypting or when 
     encrypting with block with padding disabled. 
     kCCDecodeError	Indicates improperly formatted ciphertext or
     a "wrong key" error; occurs only during decrypt
     operations. 
     */
    CCCryptorStatus CCCrypt(
                            CCOperation op,			/* kCCEncrypt, etc. */
                            CCAlgorithm alg,		/* kCCAlgorithmAES128, etc. */
                            CCOptions options,		/* kCCOptionPKCS7Padding, etc. */
                            const void *key,
                            size_t keyLength,
                            const void *iv,			/* optional initialization vector */
                            const void *dataIn,		/* optional per op and alg */
                            size_t dataInLength,
                            void *dataOut,			/* data RETURNED here */
                            size_t dataOutAvailable,
                            size_t *dataOutMoved);	
    
#ifdef __cplusplus
}
#endif

#endif	/* _CC_COMMON_CRYPTOR_ */